/* testfiles.c
 *	Simple program to test the file handling system calls
 */

#include "syscall.h"



  OpenFileId fd;
  int bytesread;
  char buf[30];
  int lockID;
  int condID;
  int newLockIndex;
  int newCondIndex;
  int i;
  char * choice;
  int errorCode;
  int threadReady;
  /*-----------User Variables------------*/
  int MAX_LOCKS;  /* MUST CHANGE TO OS VARIABLE! */
  int MAX_CONDITIONS;
  int MAX_THREADS;
  int testTenLock;
  int testTenCV;
  int threadNum;







void test1(){
/* Test 1 */
	
    Write("\n\nStarting Test 1\n", 21, ConsoleOutput);

	lockID = -1;
    lockID = CreateLock();
	if(lockID != -1){
		Write("Lock Created\n", 14, ConsoleOutput);
	}

	Write("End of Test 1\n\n", 17, ConsoleOutput);
	return;
}

void test2(){
/* Test 2 */
	
	MAX_LOCKS = 500;
	
    Write("\n\nStarting Test 2\n", 21, ConsoleOutput);
	newLockIndex = 0;
	i=0;

	for(i = 0; i < (MAX_LOCKS); i++){
		newLockIndex = CreateLock();
		if(newLockIndex != -1){
			Write("Lock Created\n", 14, ConsoleOutput);
		}else{
			Write("Lock Denied\n", 13, ConsoleOutput);
		}
	}
	i = 0;

	Write("OS should have denied 1 lock creation\n", 39, ConsoleOutput);
	Write("End of Test 2\n\n", 17, ConsoleOutput);
	return;
}
	
void test3(){
/* Test 3 */
	
    Write("\n\nStarting Test 3\n", 21, ConsoleOutput);

	lockID = CreateLock();
	AcquireLock(lockID);
	Write("Lock has been acquired.\n", 25, ConsoleOutput);	
	ReleaseLock(lockID);
	Write("Lock has been released.\n", 25, ConsoleOutput);

	Write("End of Test 3\n\n", 17, ConsoleOutput);
	return;
}
	
void test4(){
/* Test 4 */

    Write("\n\nStarting Test 4\n", 21, ConsoleOutput);
	
	lockID = 1;
	Write("About to release lock it doesn't own.\n", 39, ConsoleOutput);
	ReleaseLock(lockID);

	Write("End of Test 4\n\n", 17, ConsoleOutput);
	return;
}
	
void test5(){
/* Test 5 */

    Write("\n\nStarting Test 5\n", 21, ConsoleOutput);

	lockID = CreateLock();
	AcquireLock(lockID);
	Write("Lock has been acquired.\n", 25, ConsoleOutput);
	Write("Going to try to acquire lock again.\n", 37, ConsoleOutput);
	AcquireLock(lockID);
	ReleaseLock(lockID);
	Write("Lock has been released.\n", 25, ConsoleOutput);

	Write("End of Test 5\n\n", 17, ConsoleOutput);
	return;
}
	
void test6(){
/* Test 6 */
	
    Write("\n\nStarting Test 6\n", 21, ConsoleOutput);

	lockID = CreateLock();
	AcquireLock(lockID);
	DestroyLock(lockID);
	ReleaseLock(lockID);
	Write("Lock has been destroyed.\n", 26, ConsoleOutput);
	Write("About to Acquire deleted lock.\n", 32, ConsoleOutput);
	AcquireLock(lockID);
	Write("OS should have denied the Acquire.\n", 36, ConsoleOutput);

	Write("End of Test 6\n\n", 17, ConsoleOutput);
	return;
}
	
void t7_1(){
	Write("t7_1: Hello World!\n", 19, ConsoleOutput);
	Write("t7_1: Attempting to acquire Lock.  I should not succeed..\n", 58, ConsoleOutput);
	threadReady = 1;
	AcquireLock(lockID);
	Write("t7_1: uh oh, I acquired the lock...\n", 36, ConsoleOutput);
	Exit(0);
}
void test7(){	
	/* Test 7 */

    Write("\n\nStarting Test 6\n", 19, ConsoleOutput);

	lockID = CreateLock();
	AcquireLock(lockID);
	Write("Lock has been acquired.\n", 24, ConsoleOutput);	
	Write("Will now make another thread that tries to acquire my Lock.\n",60,ConsoleOutput);
	Fork(t7_1);
	while(threadReady == 0){
		Yield();
	}
	Write("End of Test 7\n\n", 17, ConsoleOutput);
	
	return;
}	
	
void test8(){
/* Test 8 */

    Write("\n\nStarting Test 8\n", 18, ConsoleOutput);

	condID = -1;
    condID = CreateCondition();
	if(condID != -1){
		Write("Condition Created\n", 18, ConsoleOutput);
	}
	
	Write("End of Test 8\n\n", 15, ConsoleOutput);
	return;
}
	
void test9(){
/* Test 9 */
	
	MAX_CONDITIONS = 500;
	
    Write("\n\nStarting Test 9\n", 21, ConsoleOutput);
	newCondIndex = 0;

	for(i = 0; i < (MAX_CONDITIONS); i++){  /*TODO: remove -1 (compensate for test 8) */
		newCondIndex = CreateCondition();
		if(newCondIndex != -1){
			Write("Condition Created\n", 19, ConsoleOutput);
		}else{
			Write("Condition Denied\n", 18, ConsoleOutput);
		}
	}
	i = 0;

	Write("OS should have denied 1 condition creation\n", 44, ConsoleOutput);
	Write("End of Test 9\n\n", 17, ConsoleOutput);
	return;
}
	
void t10_1(){
   int myLock;
   int myCond;
    Write("t10_1: Hello World!\n", 20, ConsoleOutput);
	Write("t10_1: I'm going to acquire the lock\n", 37, ConsoleOutput);
	myLock = 1;
	AcquireLock(testTenLock);
	Write("t10_1: I'm going to wait on the condition for the lock\n", 55, ConsoleOutput);
	myCond = 1;
	threadReady = 1;
	Wait(testTenCV, testTenLock);
	ReleaseLock(testTenLock);
	threadReady++;
    Write("t10_1: I have been woken up!\n", 29, ConsoleOutput);
	Exit(0);
}
void t10_2(){
   int myLock;
   int myCond;
    Write("t10_2: Hello World!\n", 20, ConsoleOutput);
	Write("t10_2: I'm going to acquire the lock.\n", 38, ConsoleOutput);
	myLock = 1;
	AcquireLock(testTenLock);
	Write("t10_2: I'm going to signal on the condition for the lock.\n", 58, ConsoleOutput);
	myCond = 1;
	Signal(testTenCV, testTenLock);
	ReleaseLock(testTenLock);
    Write("t10_2: I told them to wake up.\n", 31, ConsoleOutput);
	threadReady++;
	Exit(0);
}
void test10(){
/* Test 10 */
	
    Write("\n\nStarting Test 10\n", 19, ConsoleOutput);

	testTenLock = CreateLock();
	testTenCV = CreateCondition();
	threadReady = 0;
	Fork(t10_1);
	while(threadReady == 0){
		Yield();
	}
	threadReady = 0;
	Fork(t10_2);
	while(threadReady <= 1){
		Yield();
	}	

	Write("End of Test 10\n\n", 16, ConsoleOutput);
	return;
}

void t11(){
	Write("I am a thread!\n", 15, ConsoleOutput);
	/*Printing("I am thread %i\n", ConsoleOutput, threadNum, 0);*/
	/*Exit(0);*/
	if(i == MAX_THREADS*20){
		Exit(0);
	} else {
		Yield();
	}
}
void test11(){
	/* test 11 - make a crap ton of threads */
	MAX_THREADS = 100;
	threadNum = 0;
	Write("Starting Test 11, should print 99 threads\n", 42, ConsoleOutput);
	for(i = 0; i < MAX_THREADS*20; i++){
	/*i = 0;
	while(1){*/
		Printing("Attempting to fork thread %i\n", ConsoleOutput, i, 0);
		/*i++;*/
		Fork(t11);

	}	
}

void test12(){
	Write("\n\nStarting Test 12\n", 19, ConsoleOutput);
	
	errorCode = Exec("../test/testP3", 14);
	/*Exec("../test/testP3");*/
	Printing("Exec error code = %i\n", ConsoleOutput, errorCode, 0);
	/*Exit(0);*/
	return;
}

void t13_1(){
    Write("This should print 1st.\n", 23, ConsoleOutput);
	Exit(0);
}
void test13(){
/* Test 13 */

    Write("\n\nStarting Test 13\n", 19, ConsoleOutput);

	Fork(t13_1);
	
	Yield();
    Write("This should print 2nd.\n", 23, ConsoleOutput);
	
	Write("End of Test 13\n\n", 16, ConsoleOutput);
	return;
}

void test14(){
/* Test 14 */

    Write("\n\nStarting Test 14\n", 19, ConsoleOutput);

	lockID = CreateLock();
	condID = CreateCondition();
    Write("About to Wait on condition.\n", 28, ConsoleOutput);
	Wait(condID, lockID);
    Write("This should not print.\n", 23, ConsoleOutput);
	
	Write("End of Test 13\n\n", 16, ConsoleOutput);
	return;
}

void t15_1(){
	AcquireLock(lockID);
	Write("t15_1 waiting on Condition.\n", 28, ConsoleOutput);
	threadReady++;
	Wait(condID, lockID);
	threadReady++;
	Write("t15_1 has been awoken!\n", 23, ConsoleOutput);
	ReleaseLock(lockID);
	Exit(0);
}
void t15_2(){
	AcquireLock(lockID);
	Write("t15_2 waiting on Condition.\n", 28, ConsoleOutput);
	threadReady++;
	Wait(condID, lockID);
	threadReady++;
	Write("t15_2 has been awoken!\n", 23, ConsoleOutput);
	ReleaseLock(lockID);
	Exit(0);
}
void test15(){
/* Test 15 */
	Write("\n\nStarting Test 15\n", 19, ConsoleOutput);
	
	lockID = CreateLock();
	condID = CreateCondition();
	threadReady = 0;
	Fork(t15_1);
	Fork(t15_2);
	while(threadReady<=1){
		Yield();
	}
	AcquireLock(lockID);
	threadReady = 0;
	Write("About to Broadcast.\n", 20, ConsoleOutput);
	threadReady = 0;
	Broadcast(condID, lockID);
	ReleaseLock(lockID);
    Write("Broadcast complete.\n", 20, ConsoleOutput);
	while(threadReady<=1){
		Yield();
	}
	
	Write("End of Test 15\n\n", 16, ConsoleOutput);
	Exit(0);
	return;
}

void test16(){
/* Test 16 */
Write("\n\nStarting Test 16\n", 19, ConsoleOutput);
	
	lockID = CreateLock();
	
	Write("About to attempt acquire with bogus ID.\n", 40, ConsoleOutput);
	AcquireLock('g');
	
	Write("End of Test 16\n\n", 16, ConsoleOutput);
	return;
}

void test17(){
	Write("\n\nStarting Test 17\n", 19, ConsoleOutput);
	
	Printing("---Example 1: Normal Printing\n", ConsoleOutput, 0, 0);	
	Printing("This print statement should print.\n", ConsoleOutput, 0, 0);
	Printing("-----End of the last print statement\n", ConsoleOutput, 0, 0);


	Printing("---Example 2: Normal Printing with an int.\n", ConsoleOutput, 0, 0);	
	Printing("This statement should print an integer here: %i\n", ConsoleOutput, 1, 0);
	Printing("-----End of the last print statement\n", ConsoleOutput, 0, 0);

	
	Printing("---Example 3: Normal Printing with two ints\n", ConsoleOutput, 0, 0);
	Printing("This statement should print two integers here: %i, %i\n", ConsoleOutput, 23,43);
	Printing("-----End of the last print statement\n", ConsoleOutput, 0, 0);

	
	Printing("---Example 4: Normal Printing with a negative int\n", ConsoleOutput, 0, 0);
	Printing("This statement should print a negtaive integer: %i\n", ConsoleOutput, -23, -87);
	Printing("-----End of the last print statement\n", ConsoleOutput, 0, 0);

	
	Printing("---Example 5: Normal Printing with a split in the middle of the line.\n", ConsoleOutput, 0, 0);
	Printing("This statement should split\0", ConsoleOutput, 0, 0);
	Printing(" without you noticing\n", ConsoleOutput, 0, 0);
	Printing("-----End of the last print statement\n", ConsoleOutput, 0, 0);

	
	Write("End of Test 17\n\n", 16, ConsoleOutput);
}

void test18(){ 

	Write("\n\nStarting Test 18\n", 19, ConsoleOutput);
	
	Printing("\n", ConsoleOutput, 0, 0);
	Printing("---Example 1: Throwing an error because trying to print a non-int number character.\n", ConsoleOutput, 0, 0);
	Printing("This print statement should print an error because the special character input is incorrect %d.\n", ConsoleOutput, 0, 0);
	Printing("-----End of the last print statement\n", ConsoleOutput, 0, 0);
	Printing("\n", ConsoleOutput, 0, 0);

	Printing("\n", ConsoleOutput, 0, 0);
	Printing("---Example 2: Demonstrating that print statements must end in an endline or null character and no other special char.\n", ConsoleOutput, 0, 0);
	Printing("This print statement should print garbage (old print statements or blank space) because the breaking character is incorrect.\t", ConsoleOutput, 0, 0);
	Printing("-----End of the last print statement\n", ConsoleOutput, 0, 0);
	Printing("\n", ConsoleOutput, 0, 0);
	
	Printing("\n", ConsoleOutput, 0, 0);
	Printing("---Example 3: Demonstrating that print statements will only print up to 200 chars.\n", ConsoleOutput, 0, 0);
	Printing("This print statement should print get cut off because it character length is much longer than it should be.  I am going to keep writing to make the statement exceed 200 char and I'm almost there I believe in a few.....\n", ConsoleOutput, 0, 0);
	Printing("-----End of the last print statement\n", ConsoleOutput, 0, 0);
	Printing("\n", ConsoleOutput, 0, 0);
	
	Printing("\n", ConsoleOutput, 0, 0);
	Printing("---Example 4: Demonstrating that print statements must endline or null character and not just an ordinary char\n", ConsoleOutput, 0, 0);
	Printing("This statement will print garbage (probably from the last print statement, or unpredictable printing) since the ending char is not correct.\n", ConsoleOutput, 0, 0);
	Printing("-----End of the last print statement\n", ConsoleOutput, 0, 0);
	Printing("\n", ConsoleOutput, 0, 0);
	
	Write("\n\nEnding Test 18\n", 17, ConsoleOutput);

}

void test19(){

	

	Write("\n\nStarting Test 19\n", 19, ConsoleOutput);
	
	Printing("Printing a random int 0 - 99 for demo purposes, the order should change with different rs's: %i\n", ConsoleOutput,Random()%100,0);
	Printing("Printing a random int 0 - 99 for demo purposes, the order should change with different rs's: %i\n", ConsoleOutput,Random()%100,0);
	Printing("Printing a random int 0 - 99 for demo purposes, the order should change with different rs's: %i\n", ConsoleOutput,Random()%100,0);
	Printing("Printing a random int 0 - 99 for demo purposes, the order should change with different rs's: %i\n", ConsoleOutput,Random()%100,0);

	Write("\n\nEndind Test 19\n", 17, ConsoleOutput);


}

void test21(){
/* Test 21 */
Write("\n\nStarting Test 21\n", 19, ConsoleOutput);
	
	lockID = CreateLock();
	AcquireLock(lockID);
	
	Write("About to attempt release with bogus ID.\n", 40, ConsoleOutput);
	ReleaseLock("hit");
	
	Write("End of Test 21\n\n", 16, ConsoleOutput);
	return;
}

void test22(){
/* Test 22 */
Write("\n\nStarting Test 22\n", 19, ConsoleOutput);
	
	lockID = CreateLock();
	condID = CreateCondition();
	
	Write("About to attempt Signal with bogus ID combos.\n", 46, ConsoleOutput);
	Signal("foo", lockID);
	Signal(condID, "bar");
	Signal("foo", "bar");

	Write("About to attempt Broadcast with bogus ID combos.\n", 49, ConsoleOutput);
	Broadcast("foo", lockID);
	Broadcast(condID, "bar");
	Broadcast("foo", "bar");
	
	Write("About to attempt Wait with bogus ID combos.\n", 44, ConsoleOutput);
	Wait("foo", lockID);
	Wait(condID, "bar");
	Wait("foo", "bar");
	
	Write("End of Test 22\n\n", 16, ConsoleOutput);
	return;	
}

void test23(){
/* Test 23 */
	
}

void testOneTheater(){
	Write("\n\nNow starting one instance of Theater\n\n", 40, ConsoleOutput);
	errorCode = Exec("../test/theater", 15);
}

void testTwoTheaters(){
	Write("\n\nNow starting two instances of Theater\n\n", 41, ConsoleOutput);
	errorCode = Exec("../test/theater", 15);
	errorCode = Exec("../test/theater", 15);
}

void testTwoTheatersTabbed(){
	Write("\n\nNow starting two instances of Theater\n\n", 41, ConsoleOutput);
	errorCode = Exec("../test/theater", 15);
	errorCode = Exec("../test/theater2", 16);
}

void submenu3(){
	return;
}

void submenu2(){

	Write("Please choose of the following options.\n", 40, ConsoleOutput);
	Write("1. Printing System Call.\n", 25, ConsoleOutput);
	Write("2. Printing System Call Breaks.\n", 32, ConsoleOutput);
	Write("3. Demonstrating Random\n", 24, ConsoleOutput);
	Write("4. None\n", 8, ConsoleOutput);
	Write("5. Attempting a Release with bogus index.\n", 42, ConsoleOutput);
	Write("6. Testing all bogus input combos for Condition.\n", 49, ConsoleOutput);

	Read(choice, 1, ConsoleInput);
	
	if(*choice == '1'){
		test17();
	}
	else if(*choice == '2'){
		test18();
	}
	else if(*choice == '3'){
		test19();
	}
	else if(*choice == '5'){
		test21();
	}
	else if(*choice == '6'){
		test22();
	}
	else{
		Write("Error handling input.\n", 22, ConsoleOutput);
	}
	
	return;

}

void submenu1(){

	Write("Please choose of the following options.\n", 40, ConsoleOutput);
	Write("1. Creating too many Conditions.\n", 33, ConsoleOutput);
	Write("2. 2 threads, 1 cv.\n", 20, ConsoleOutput);
	Write("3. A lot of threads\n", 20, ConsoleOutput);
	Write("4. 2 processes\n", 15, ConsoleOutput);
	Write("5. Yield Test 1.\n", 17, ConsoleOutput);
	Write("6. Last running thread Waits\n", 29, ConsoleOutput);
	Write("7. Normal Broadcast test\n", 25, ConsoleOutput);
	Write("8. Bogus ID to access Lock\n", 27, ConsoleOutput);	
	Write("9. More...\n", 11, ConsoleOutput);

	Read(choice, 1, ConsoleInput);
	
	if(*choice == '1'){
		test9();
	}
	else if(*choice == '2'){
		test10();
	}
	else if(*choice == '3'){
		test11();
	}
	else if(*choice == '4'){
		test12();
	}
	else if(*choice == '5'){
		test13();
	}
	else if(*choice == '6'){
		test14();
	}
	else if(*choice == '7'){
		test15();
	}
	else if(*choice == '8'){
		test16();
	}
	else if(*choice == '9'){
		submenu2();
	}
	else{
		Write("Error handling input.\n", 22, ConsoleOutput);
	}
	
	return;

}
	
void menu(){

	Write("Please choose of the following options.\n", 40, ConsoleOutput);
	Write("a. Start one Theater simulation.\n", 33, ConsoleOutput);
	Write("b. Start two Theater simulations.\n", 34, ConsoleOutput);
	Write("c. Start two Theater simulations with tabbed printing.\n", 55, ConsoleOutput);
	Write("1. Lock Creation.\n", 18, ConsoleOutput);
	Write("2. Too much Lock creation.\n", 27, ConsoleOutput);
	Write("3. Normal Lock acquire and release.\n", 36, ConsoleOutput);
	Write("4. Illegal Lock release.\n", 25, ConsoleOutput);
	Write("5. Aquiring a Lock twice.\n", 26, ConsoleOutput);
	Write("6. Acquiring a destroyed lock.\n", 31, ConsoleOutput);
	Write("7. Acquiring a lock twice.\n", 27, ConsoleOutput);
	Write("8. Create Condition Test\n", 25, ConsoleOutput);
	Write("9. More...\n", 11, ConsoleOutput);

	Write("\n\nNote: only the first digit that you enter will be read.  \nFor example, input 456 will be read as choice 4.\n", 109, ConsoleOutput);
	Read(choice, 1, ConsoleInput);
	
	if(*choice == '1'){
		test1();
	}
	else if(*choice == '2'){
		test2();
	}
	else if(*choice == '3'){
		test3();
	}
	else if(*choice == '4'){
		test4();
	}
	else if(*choice == '5'){
		test5();
	}
	else if(*choice == '6'){
		test6();
	}
	else if(*choice == '7'){
		test7();
	}
	else if(*choice == '8'){
		test8();
	}
	else if(*choice == '9'){
		submenu1();
	}else if(*choice == 'a'){
		testOneTheater();
	}else if(*choice == 'b'){
		testTwoTheaters();
	}
	else if(*choice == 'c'){
		testTwoTheatersTabbed();
	}else{
		Write("Error handling input.\n", 22, ConsoleOutput);
	}
	return;
}

int main() {



    Create("testfile", 8);
    fd = Open("testfile", 8);

    Write("testing a write\n", 16, fd );
	Write("Starting\n", 9, ConsoleOutput);
    Close(fd);


    fd = Open("testfile", 8);
    bytesread = Read( buf, 100, fd );
    Write( buf, bytesread, ConsoleOutput );
    Close(fd);
	
	menu();
	Exit(0);
}	

